//
// Created by zain on 2017/3/14.
//

#include "EntityObject.h"

#include "Light.h"

using namespace std;
using namespace glm;

void ZainGL::EntityObject::draw(std::vector<glm::mat4> *const instanceTransforms) {
    mMaterial->active();

    GLint shadowMapLoc = glGetUniformLocation(mMaterial->mShaderLoc, "shadowMap");
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, Light::ShadowMapTextureLoc);
    glUniform1i(shadowMapLoc, 0);

    /*diffuse*/
    GLint texture_diffuseLoc = glGetUniformLocation(mMaterial->mShaderLoc, "texture_diffuse");
    uint64_t textureNum = mTextures.size();
    for (GLuint i = 0; i < textureNum; i++) {
        glActiveTexture(GL_TEXTURE1 + i);//由于GL_TEXTURE0默认被我绑定在ShadowMap上，所以这里从GL_TEXTURE1开始
        glBindTexture(GL_TEXTURE_2D, mTextures[i]->textureID);
        glUniform1i(texture_diffuseLoc, 1 + i);
    }

    glBindVertexArray(mVAO);
    glBindBuffer(GL_ARRAY_BUFFER, mIBO);
    // Buffer orphaning, a common way to improve streaming perf. See above link for details.
    if (instanceTransforms && instanceTransforms->size() > 0) {
        glBufferSubData(GL_ARRAY_BUFFER, 0, instanceTransforms->size() * sizeof(mat4), &instanceTransforms->at(0));
        glDrawElementsInstanced(GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, 0, instanceTransforms->size());
    } else {
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(mat4), value_ptr(mTransform));
        glDrawElementsInstanced(GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, 0, 1);
    }
    glBindVertexArray(0);

    //reset GL_TEXTUREs to default after drawing
    for (int16_t i = textureNum - 1; i >= 0; --i) {
        glActiveTexture(GL_TEXTURE1 + i);
        glBindTexture(GL_TEXTURE_2D, 0);
    }
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, 0);
}

void ZainGL::EntityObject::renderToShadowMap(vector<mat4> *const instanceTransforms) {
    glBindVertexArray(mVAO);
    glBindBuffer(GL_ARRAY_BUFFER, mIBO);
    if (instanceTransforms && instanceTransforms->size() > 0) {
        glBufferSubData(GL_ARRAY_BUFFER, 0, instanceTransforms->size() * sizeof(mat4), &instanceTransforms->at(0));
        glDrawElementsInstanced(GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, 0, instanceTransforms->size());
    } else {
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(mat4), value_ptr(mTransform));
        glDrawElementsInstanced(GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, 0, 1);
    }
    glBindVertexArray(0);
}
